<!--子组件-->
<template>
  <div id="box">
    <p><b>组件接收 prop ,组件事件注册和监听</b></p>
    <p><b>prop 为基本类型：</b>{{ id }}-{{ normalizedTitle }}</p>
    <p><b>prop 为数组：</b></p>
    <ul>
      <li v-for="item in arr" :key="item">{{ item }}</li>
    </ul>
    <p><b>prop 带有validator校验：</b> {{ validatorProp }}</p>
    <p><b>prop 为方法：</b>{{ fns }}</p>
    <p>
      <b>组件事件注册和监听: </b>
      <button @click="bfn">注册事件</button>
    </p>
    <hr />
    <p><b>组件使用 v-model 实现双向绑定</b></p>
    <input type="text" v-model="firstName" />
    <input type="text" v-model="lastName" />
    <hr />
    <p><b>透传属性</b></p>
    <p><b>获取透传过来的class 属性：</b>{{ $attrs["class"] }}</p>
    <hr />
    <p>
      <b>插槽 插槽一般作用在需要同时复用逻辑和视图布局时使用--无渲染组件（作用域插槽）,纯逻辑复用时使用--组合式函数</b>
    </p>
    <slot name="main"></slot>
    <slot name="foot"></slot>
    <p><b>向一个插槽的出口上传递 属性</b></p>
    <slot name="slotProp" :text="greetingMessage" :count="1"></slot>
    <div>
      <h3>高级列表插槽:</h3>
      <ul>
        <li v-if="!itemSlot.length">加载中...</li>
        <li v-for="item in itemSlot" :key="item.username">
          <slot name="listSlot" v-bind="item"></slot>
        </li>
      </ul>
    </div>
    <hr />
  </div>
</template>

<script setup lang="ts">
// const props = defineProps<{
//   id?: number | undefined;
//   title: String;
// }>();

import { defineModel } from "vue";
import { propTypes } from "@/utils/propTypes";
//  组件接收 prop 定义
const props = defineProps({
  id: propTypes.number.isRequired,
  title: propTypes.string,
  arr: propTypes.array.def(["success", "warning", "danger"]),
  validatorProp: propTypes.string.validate((v: string) => ["success", "warning", "danger"].includes(v)),
  fns: propTypes.func.def(() => "我是函数默认返回值")
});

// 组件注册事件
// 只是将 props.id 作为初始值,像下面这样做就使  id 和后续更新无关了
// const postId = ref(props.id);
// 该 title 变更时计算属性也会自动更新
const normalizedTitle = computed(() => props.title.trim().toLowerCase());

// 宏声明要抛出的事件
// 1. 简单定义
// const emit = defineEmits(['change'])
// 2. 基于选项
// const emit = defineEmits({
//   enlarge: (color?: string) => {
//     // 返回 `true` 或 `false`
//     // 表明验证通过或失败
//     return true;
//   }
// });
// 3. 基于类型
// const emit = defineEmits<{ (e: "enlarge", color?: string): void }>();
// 4. 3.3+: 可选的、更简洁的语法
const emit = defineEmits<{ enlarge: [color?: string] }>();

// 点击触发抛出的事件
const bfn = () => {
  emit("enlarge", "beige");
};

// v-model 可以在组件上使用以实现双向绑定。
const firstName = defineModel<string>("firstName");

// 处理 v-model 修饰符,自定义修饰符upper,完成首字母大写
const [lastName, modifiers] = defineModel<string>("mm", {
  set(value) {
    if (modifiers.upper) {
      return value.charAt(0).toUpperCase() + value.slice(1);
    }
    return value;
  }
});
// 禁用属性透传
defineOptions({
  inheritAttrs: false
});

const greetingMessage = "作用域插槽 向对组件传递 props 那样，向一个插槽的出口上传递";

const itemSlot = ref([]);
// mock remote data fetching
setTimeout(() => {
  itemSlot.value = [
    { body: "Scoped Slots Guide", username: "Ev ", likes: 20 },
    { body: "Vue Tutorial", username: "Natalia", likes: 10 }
  ];
}, 2000);
</script>

<style scoped>
ul {
  padding: 5px;
  list-style-type: none;
  background: linear-gradient(315deg, #42d392 25%, #647eff);
}

li {
  padding: 5px 20px;
  margin: 10px;
  background: #fff;
}
</style>
